package com.example.myapplication;

import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Switch;

import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.example.jtt1078_audio.callback.OnMicrophoneData;
import com.example.jtt1078_audio.constants.Constants;
import com.example.jtt1078_audio.encoder.Frame;
import com.example.jtt1078_audio.encoder.audio.AudioEncoder;
import com.example.jtt1078_audio.encoder.audio.GetAacData;
import com.example.jtt1078_audio.encoder.input.GetMicrophoneData;
import com.example.jtt1078_audio.encoder.utils.CodecUtil;
import com.example.jtt1078_audio.interfaces.OnDataAvailable;
import com.example.jtt1078_audio.source.MicrophoneSource;
import com.example.myapplication.service.AudioService;
import com.example.jtt1078_audio.source.AudioSource;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getName();

    private EditText ip, port, deviceId, logicalChannel;
    private Button send;
    private Switch playMySelf;

    private boolean recording = false;

    GetAacData onMicrophoneData;
    AudioSource audioSource;
    AudioEncoder audioEncoder;

    private final int microphoneBufferSize = 1024; // 麦克风每次从缓存单独拿的 size，如果是以 G711A 编码，编码后的长度会减半

    private final int sampleRate = 8000; // 采样率
    private final boolean isStereo = false; // 双声道还是单声道
    private final boolean echoCanceler = true; // 消除回声
    private final boolean noiseSuppressor = true; // 降噪
    private final int bitrate = 128 * 1000; // 这个码率没做修改，是之前 aac 的配置

    private final int requestPermissionCode = 0x99;

    private GetMicrophoneData getMicrophoneData = new GetMicrophoneData() {
        @Override
        public void inputPCMData(@NonNull Frame frame) {
            audioEncoder.inputPCMData(frame);
        }
    };

    private boolean prepared = false; // 音频初始化成功与否

    // 音频播放服务
    private AudioService audioService;
    private ServiceConnection serviceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        initView();
        initData();
        initService();
    }

    private void initView(){
        ip = findViewById(R.id.ip);
        port = findViewById(R.id.port);
        deviceId = findViewById(R.id.deviceId);
        logicalChannel = findViewById(R.id.logicalChannel);
        send = findViewById(R.id.send);
        playMySelf = findViewById(R.id.play_myself);

        ip.setText(Constants.ip);
        port.setText(String.valueOf(Constants.port));
        deviceId.setText(Constants.deviceId);
        logicalChannel.setText(String.valueOf(Constants.logicalChannel));

        send.setOnClickListener(v->{
            if(!recording){
                String ipStr = ip.getText().toString();
                int portNum = Integer.parseInt(port.getText().toString());
                String deviceIdStr = deviceId.getText().toString();
                int logicalChannelNum = Integer.parseInt(logicalChannel.getText().toString());
                Log.d(TAG, String.format("ip %s port %d deviceId %s logicalChannel %d", ipStr, portNum, deviceIdStr, logicalChannelNum));
                onMicrophoneData.setSocketInfo(ipStr, portNum, deviceIdStr, logicalChannelNum);
                startAudio();
                recording = true;
                send.setText(getString(R.string.stop));
            }else{
                stopAudio();
                recording = false;
                send.setText(getString(R.string.send));
            }
        });

        playMySelf.setOnCheckedChangeListener((v,b)->{
            if(b){
                Constants.playMyself = true;
            }else{
                Constants.playMyself = false;
            }
        });
        playMySelf.setChecked(Constants.playMyself);

    }

    private void initData(){
        audioSource = new MicrophoneSource();
        audioSource.setMaxInputSize(microphoneBufferSize); // 在 prepare 之前配置 麦克风每次从缓存单独拿的 size
        onMicrophoneData = new OnMicrophoneData();
        onMicrophoneData.setOnDataAvailable(new OnDataAvailable() {
            @Override
            public void onData(byte[] data) {
                if(audioService != null){
                    audioService.onAudioData(data);
                }
            }
        });
        audioEncoder = new AudioEncoder(onMicrophoneData);
        audioEncoder.setType(CodecUtil.G711_MIME); // 在 prepare 之前配置对应的编码格式，视频默认 h264，音频默认 aac
    }

    private void initService(){
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                audioService = ((AudioService.MyBinder) service).getService();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
        Intent intent = new Intent(this, AudioService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkPermission();
    }

    @Override
    protected void onDestroy() {

        if(serviceConnection != null){
            unbindService(serviceConnection);
        }
        super.onDestroy();
    }



    private void checkPermission(){
        if(ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
        != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, requestPermissionCode);
        }else{
            prepare();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == requestPermissionCode){
            int index = 0;
            for (String permission : permissions){
                if(permission.equals(Manifest.permission.RECORD_AUDIO)){
                    if(grantResults[index] == PackageManager.PERMISSION_GRANTED){
                        prepare();
                    }
                }
                index++;
            }
        }
    }

    private void prepare(){
        if(!prepared){
            prepared = prepareAudio();
            if(!prepared){
                Log.e(TAG, "Audio configuration failed");
            }
        }

    }

    private boolean prepareAudio(){
        if(recording){
            Log.e(TAG, "recording now, can't call this method");
            return false;
        }
        boolean result = audioSource.init(sampleRate, isStereo, echoCanceler, noiseSuppressor);
        if(result){
            return audioEncoder.prepareAudioEncoder(bitrate, sampleRate, isStereo, audioSource.getMaxInputSize());
        }
        return false;
    }

    private void startAudio(){
        prepare();
        if(prepared){
            onMicrophoneData.start();
            audioSource.start(getMicrophoneData);
            audioEncoder.start(System.nanoTime() / 1000);
        }

    }

    private void stopAudio(){
        prepared = false;
        onMicrophoneData.stop();
        audioSource.stop();
        audioEncoder.stop();
        if(audioService != null){
            audioService.stopPlay();
        }
    }
}